Skip to content

feat: Add terminal management tools with output capture to mcp-server-vscode#659

Open
psh4607 wants to merge 1 commit into
microsoft:mainfrom
psh4607:feat/terminal-tools-all
Open

feat: Add terminal management tools with output capture to mcp-server-vscode#659
psh4607 wants to merge 1 commit into
microsoft:mainfrom
psh4607:feat/terminal-tools-all

Conversation

@psh4607
Copy link
Copy Markdown

@psh4607 psh4607 commented Mar 27, 2026

Summary

Add five terminal management tools to the VSCode MCP Server extension, enabling AI assistants to create, control, and read output from VS Code integrated terminals via MCP.

This builds on the existing tool patterns (debug_tools, focus_editor) and adds a frequently requested capability: programmatic terminal access for AI-powered development workflows.

New Tools

Tool Description
create_terminal Create a new terminal with optional name, working directory, and initial command
list_terminals List all active terminals in the workspace
send_terminal_text Send text/commands to an existing terminal by name
close_terminal Close a terminal by name
get_terminal_output Read captured per-command output with pagination support

Design Decisions & Trade-offs

Output Capture: Why Shell Execution Events (not file-based)

We explored three approaches for reading terminal output before settling on the current design:

Approach A: Passive capture via onDidWriteTerminalData (rejected)

  • Captures raw terminal data stream to temp files on disk
  • Pros: Captures everything, works without shell integration
  • Cons: onDidWriteTerminalData is a proposed API, not available in stable @types/vscode. Also raises security concerns — terminal output (which may contain environment variables, API keys, passwords) would be persisted to disk files, creating a larger attack surface than xterm.js's in-memory scrollback buffer.

Approach B: File-based storage (rejected)

  • Append-only files in os.tmpdir() with get_terminal_output(name, offset, limit, stripAnsi) pagination
  • While this is memory-efficient (OS page cache handles caching) and suits the write-heavy/read-occasional pattern, the security concern remains: sensitive terminal data on disk survives terminal closure and VS Code restarts, is readable by other processes, and could be forensically recovered after deletion.
  • Note: We considered that xterm.js already holds the same data in memory, and ~/.zsh_history persists commands to disk — so the threat model isn't dramatically different. Still, adding a new persistence vector seemed unnecessary when a better stable API exists.

Approach C: Shell execution events (chosen) ✅

  • Uses onDidStartTerminalShellExecution + TerminalShellExecution.read() (stable since VS Code 1.93)
  • Per-command structured output, already stripped of ANSI escape codes
  • In-memory only (max 50 commands per terminal), auto-cleaned on terminal close
  • Zero disk persistence = zero security concern
  • Requires shell integration (enabled by default in VS Code 1.93+)

Architecture

terminal_output_capture.ts (utils)
  └─ onDidStartTerminalShellExecution listener
  └─ Per-command output stored in Map<terminalName, CommandRecord[]>
  └─ Auto-cleanup on terminal close + extension deactivation

terminal_tools.ts (tools)
  └─ create_terminal, list_terminals, send_terminal_text, close_terminal
  └─ get_terminal_output (reads from capture module)

extension.ts
  └─ Tool registration + capture initialization

Expected Impact

  • AI-assisted terminal workflows: AI assistants can create terminals, run commands, and read results — enabling automated build/test/deploy cycles
  • Debugging support: Read command output to diagnose build failures, test results, or runtime errors without manual copy-paste
  • Multi-terminal orchestration: Manage multiple terminals programmatically (e.g., start a dev server in one, run tests in another, read both outputs)

Files Changed

File Description
src/tools/terminal_tools.ts 5 tool implementations with Zod schema validation
src/utils/terminal_output_capture.ts Shell execution event listener + in-memory command history
src/test/terminal_tools.test.ts Schema validation unit tests for all 5 tools
src/extension.ts Tool registrations + capture initialization

Testing

  • TypeScript compilation (tsc): passing
  • Webpack build: passing
  • Schema validation tests: passing
  • Runtime testing requires VS Code Extension Development Host (F5)

Add five terminal management tools enabling AI assistants to create,
control, and read output from VS Code integrated terminals via MCP.

Tools: create_terminal, list_terminals, send_terminal_text,
close_terminal, get_terminal_output

Output capture uses the stable shell execution API (1.93+) instead
of the proposed onDidWriteTerminalData, storing per-command results
in memory with no disk persistence.
@psh4607
Copy link
Copy Markdown
Author

psh4607 commented Mar 27, 2026

Note: This PR (#659) includes all 5 terminal tools — the 4 management tools from #658 plus get_terminal_output with shell execution-based output capture.

If the output capture approach (onDidStartTerminalShellExecution + in-memory command history) needs further discussion or review, #658 is a standalone subset containing only the 4 terminal management tools (create_terminal, list_terminals, send_terminal_text, close_terminal) that can be reviewed and merged independently.

Happy to iterate on either PR based on your feedback!

@psh4607
Copy link
Copy Markdown
Author

psh4607 commented Mar 27, 2026

@microsoft-github-policy-service agree

@psh4607
Copy link
Copy Markdown
Author

psh4607 commented May 23, 2026

dev-agents review: Completed

Attempt: #104
Result: COMMENT
Review: #659 (review)
Head: e28000a
Submitted: 2026-05-23T12:44:18Z
Findings: 3

Copy link
Copy Markdown
Author

@psh4607 psh4607 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment 남깁니다.

P2

  • processId가 Thenable로 직렬화되어 실제 PID가 유실됨 [critical] (src/tools/terminal_tools.ts:43)
    terminal.processIdThenable<number | undefined>를 반환합니다. extension.ts:236에서 JSON.stringify(item.json) 호출 시 Thenable 객체가 {}로 직렬화되어 MCP 클라이언트가 실제 PID를 받지 못합니다.

    제안: listTerminals를 async로 변경하고 Promise.all로 processId를 resolve:

    export const listTerminals = async () => {
        const terminals = await Promise.all(
            vscode.window.terminals.map(async (terminal, index) => ({
                index,
                name: terminal.name,
                processId: await terminal.processId,
            })),
        );
        // ...
    };

    extension.ts:233의 핸들러에서도 await listTerminals()로 변경 필요.

P3

  • 터미널 이름 기반 키 사용으로 동일 이름 터미널 간 데이터 충돌 가능 (src/utils/terminal_output_capture.ts:9)
    commandHistoryterminal.name을 키로 사용하는데, VS Code는 동일 이름의 터미널을 허용합니다. 동일 이름 터미널이 2개 이상 존재하면 출력 히스토리가 혼합되고, onDidCloseTerminal (L52)이 동일 이름의 다른 터미널 히스토리도 삭제합니다. debug_tools.tsstopDebugSession도 동일하게 이름 기반이므로 프로젝트 내 일관된 패턴이지만, 최소한 create_terminal 도구의 description에 고유한 이름 사용을 권장하는 문구를 추가하는 것을 고려해주세요.

  • 출력 캡처 리스너에 에러 핸들링 부재 (src/utils/terminal_output_capture.ts:29)
    for await (const data of execution.read())에 try-catch가 없어서, 스트림 에러 발생 시 해당 커맨드 레코드가 저장되지 않고 에러가 unhandled promise rejection으로 전파됩니다. VS Code extension host가 이를 잡아주긴 하지만, 출력 캡처 기능의 신뢰성을 위해 try-catch 추가를 고려해주세요.

    try {
        for await (const data of execution.read()) {
            chunks.push(data);
        }
    } catch (err) {
        chunks.push(`[Error reading output: ${err}]`);
    }

ℹ️ Read-only 리뷰 모드

이 repo owner는 UNWATCHED_REVIEW_TRUSTED_OWNERS에 포함되어 있지 않아 dependency install/build/test를 실행하지 않았습니다. diff 기반 코드 리뷰만 진행했습니다.


🔄 수동 재리뷰: PR 우측 사이드바 Reviewers 섹션의 Re-request review 버튼(아래 빨간 박스)을 누르면 이 봇이 다시 리뷰합니다.

Re-request review 버튼

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant